package jnpf.engine.util.xml;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import jnpf.engine.custom.exception.UnSupportExpressionException;
import jnpf.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.ast.OpAnd;
import org.springframework.expression.spel.ast.OpOr;
import org.springframework.expression.spel.ast.SpelNodeImpl;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.util.*;

/**
 * 流程引擎条件表达式解析器 目前支持单线程串行调用
 */
public class ComplexSpELToProperCondParser {

    private static final Map<String, Long> condIdMap = new HashMap<>();

    private static final Map<String, String> charMap = new HashMap<>();

    private static final SpelExpressionParser parser = new SpelExpressionParser();

    private static final String DEFAULT_LOGIC = "&&";
    private static final String DEFAULT_LOGICAL_LABEL = "system_cond";
    private static final String DEFAULT_LOGICAL_GROUP = "group";

    private static final Snowflake snowflake = IdUtil.getSnowflake();

    static {
        charMap.put("(", "(");
        charMap.put(")", ")");
        charMap.put("||", "或者");
        charMap.put("&&", "且");
        charMap.put("!", "!");
    }


    public static void main(String[] args) {
        String expression = "(amount > 500 || (amount < 800 && status == 'PENDING' || (amount == 1000 && amount < 20000)))  || amount < 1000 || (isActive == true || status == 'PENDING')";
        Boolean complex = SpElUtil.isComplex(expression);
        ComplexCond customCond = ComplexSpELToProperCondParser.parseUnSimpleExpressionToProperCond(expression);
        System.out.println(JSONObject.toJSONString(customCond));
    }

    /**
     * 解析和处理表达式
     *
     * @param expression
     * @return
     */
    protected static ComplexCond parseUnSimpleExpressionToProperCond(String expression) {
        // 表达式解析
        try {
            expression = trim(expression);
            // 解析表达式为 AST 节点
            SpelNodeImpl rootNode = (SpelNodeImpl) parser.parseRaw(expression).getAST();
            // 提取表达式为 ProperCond
            List<ProperCond> properConds = recursionParse(rootNode);
            // 提取表达式中的分隔符
            List<SubNode> subNodes = new ArrayList<>();
            recursionSub(subNodes, expression);
            // 生成customLogical
            List<ComplexCond.Logical> logicals = customLogical(subNodes);
            ComplexCond customCond = new ComplexCond();
            customCond.setCustomLogical(logicals);
            customCond.setCondList(properConds);
            return customCond;
        } catch (SpelParseException e) {
            throw new UnSupportExpressionException("表达式解析失败: " + expression, e);
        }
    }

    private static List<ComplexCond.Logical> customLogical(List<SubNode> subNodes) {
        List<ComplexCond.Logical> res = new LinkedList<>();
        for (SubNode subNode : subNodes) {
            res.add(new ComplexCond.Logical(charMap.get(subNode.getSub()), null, subNode.getSub()));
            if (StringUtil.isNotEmpty(subNode.getSubStr()) && condIdMap.containsKey(subNode.getSubStr())) {
                Long groupId = condIdMap.get(subNode.getSubStr());
                res.add(new ComplexCond.Logical(DEFAULT_LOGICAL_LABEL.concat("_").concat(groupId.toString()), DEFAULT_LOGICAL_GROUP, groupId));
            }
        }
        condIdMap.clear();
        return res;
    }

    private static String trim(String s) {
        s = s.trim();
        s = s.replaceAll("\r", "");
        s = s.replaceAll("\n", "");
        s = s.replaceAll("\t", "");
        s = s.replaceAll(" ", "");
        return s;
    }

    private static List<ProperCond> recursionParse(SpelNodeImpl node) {
        List<ProperCond> properCondList = new ArrayList<>();
        if (!(node instanceof OpOr) && !(node instanceof OpAnd)) {
            ProperCond properCond = new ProperCond();
            List<ProperCond.GroupsModel> groupsModels = extractGroupModel(node);
            properCond.setGroups(groupsModels);
            properCond.setId(snowflake.nextId());
            // 条件缓存
            if (CollectionUtil.isNotEmpty(groupsModels)) {
                ProperCond.GroupsModel first = CollectionUtil.getFirst(groupsModels);
                condIdMap.put(first.getField() + first.getOperator() + first.getValue(), properCond.getId());
            }
            properCondList.add(properCond);
            return properCondList;
        }
        for (int i = 0; i < node.getChildCount(); i++) {
            SpelNodeImpl child = (SpelNodeImpl) node.getChild(i);
            properCondList.addAll(recursionParse(child));
        }
        return properCondList;
    }

    private static void recursion(PriorityQueue<SubNode> queue, String s, String split, Integer startIndex) {
        String currentStr = s.substring(startIndex);
        if (!currentStr.contains(split)) {
            return;
        }
        int length = split.length();
        int index = currentStr.indexOf(split);
        queue.add(new SubNode((startIndex + index), split, length, null));
        startIndex = startIndex + index + length;
        recursion(queue, s, split, startIndex);
    }

    private static void recursionSub(List<SubNode> subNodes, String s) {
        PriorityQueue<SubNode> queue = new PriorityQueue<>(Comparator.comparing(SubNode::getIndex));
        charMap.keySet().forEach(key -> {
            recursion(queue, s, key, 0);
        });
        SubNode poll = queue.poll();
        if (null == poll) {
            return;
        }
        SubNode peek = queue.peek();
        if (peek == null) {
            int i = poll.getIndex() + poll.getSize();
            poll.setSubStr(i == s.length() ? null : s.substring(i));
        } else {
            poll.setSubStr(s.substring((poll.getIndex() + poll.getSize()), peek.getIndex()));
        }
        subNodes.add(poll);
        recursionSub(subNodes, s.substring(poll.getIndex() + poll.getSize()));
    }

    /**
     * 处理条件分支表达式 非 逻辑分支
     *
     * @param node
     * @return
     */
    private static List<ProperCond.GroupsModel> extractGroupModel(SpelNodeImpl node) {
        List<ProperCond.GroupsModel> res = new ArrayList<>();
        ProperCond.GroupsModel group = new ProperCond.GroupsModel();
        if (node.getChildCount() == 2) {
            // 二元表达式，例如 amount > 100
            group.setField(node.getChild(0).toStringAST().trim()); // 获取字段
            group.setOperator(getOperatorFromNode(node));  // 获取操作符
            group.setValue(node.getChild(1).toStringAST().trim()); // 获取值
        } else if (node.getChildCount() == 1) {
            // 单独的变量，例如 isActive
            group.setField(node.getChild(0).toStringAST().trim()); // 只有字段
        }
        // 处理逻辑表达式
        group.setLogic(DEFAULT_LOGIC);
        res.add(group);
        return res;
    }

    /**
     * 获取操作符
     *
     * @param node
     * @return
     */
    private static String getOperatorFromNode(SpelNodeImpl node) {
        // 精确获取操作符
        if (node instanceof OpAnd) {
            return "&&";
        } else if (node instanceof OpOr) {
            return "||";
        }
        // 处理其他运算符，例如 `==`, `>`, `<`
        String nodeString = node.toStringAST().trim();
        // 提取操作符 (注意：只取中间的运算符)
        if (nodeString.contains(">")) {
            return ">";
        } else if (nodeString.contains("<")) {
            return "<";
        } else if (nodeString.contains("==")) {
            return "==";
        } else if (nodeString.contains("!=")) {
            return "!=";
        }
        return nodeString; // 默认为原字符串
    }

    @Data
    @AllArgsConstructor
    public static class SubNode {
        /**
         * 分割符起始下标
         */
        private Integer index;
        /**
         * 分隔符
         */
        private String sub;
        /**
         * 分隔符长度
         */
        private Integer size;
        /**
         * 到下一分割符中间的字符串
         */
        private String subStr;
    }

}
